package com.pi.framework.web.controller;

import com.pi.framework.core.controller.BaseController;
import com.pi.framework.core.util.SecurityUtils;
import com.pi.sys.entity.Menu;
import com.pi.sys.entity.Subsystem;
import com.pi.sys.entity.User;
import com.pi.sys.service.MenuService;
import com.pi.sys.service.SubsystemService;
import com.pi.sys.service.UserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Controller
public class HomeController extends BaseController {
	private String defaultMenuName = "root.web";
	private String frontMenuName = "root.suppl";

	@Autowired
	private MenuService menuService;

	@Value("${security.oauth2.enabled:false}")
	private boolean oauth2Enabled = false;

	@Value("${security.oauth2.client.logoutUri:}")
	private String oauth2LogoutUri = null;

	@Autowired(required = false)
	private PasswordEncoder passwordEncoder;

	@Value("${application.rootUrl:}")
	private String rootUrl = "";

	@Autowired
	private SubsystemService subsysService;

	@Autowired
	private UserService userService;

	private String currentMenuName() {
		UserDetails user = SecurityUtils.getLoginUser();
		boolean front = false;
		if (user instanceof User) {
			front = ((User) user).isFront();
		}
		return front ? frontMenuName : defaultMenuName;
	}

	@GetMapping({ "/app", "/app/{id}" })
	public String app(@PathVariable(name = "id", required = false) Long id, Model model, HttpServletRequest request) {
		Subsystem subsystem = null;
		if (id != null && id > 0) {
			subsystem = subsysService.findById(id);
		}
		model.addAttribute("subsystem", subsystem);
		model.addAttribute("menus",
				menuService
						.treeMenu((subsystem != null && !StringUtils.isBlank(subsystem.getMenu())) ? subsystem.getMenu()
								: currentMenuName()));
		return view("index");
	}

	@SuppressWarnings("unchecked")
	@ModelAttribute("grantedMenus")
	public List<Menu> grantedMenus(HttpSession session) {
		if (session == null) {
			return Collections.emptyList();
		}
		UserDetails user = SecurityUtils.getLoginUser();
		if (user == null) {
			return Collections.emptyList();
		}
		List<Menu> grantedMenus = (List<Menu>) session.getAttribute("grantedMenus");
		if (grantedMenus != null && !grantedMenus.isEmpty()) {
			return grantedMenus;
		}

		List<String> roleNames = new ArrayList<>();
		user.getAuthorities().forEach(au -> roleNames.add(au.getAuthority()));
		if (!roleNames.isEmpty()) {
			grantedMenus = menuService.findByRoleNames(roleNames);
		} else {
			grantedMenus = new ArrayList<>();
		}
		session.setAttribute("grantedMenus", grantedMenus);
		return grantedMenus;
	}

	@GetMapping("/")
	public String index(Model model, HttpServletRequest request) {
		return "redirect:app";
	}

	@GetMapping("/login")
	public String login() {
		return view("login");
	}

	@GetMapping(value = "/login/fail")
	public String loginFailure(Model model) {
		String message = "Wrong password or username provided! Please try again.";
		model.addAttribute("message", message);
		return "login";
	}

	@GetMapping(value = "/login/success")
	public String loginSuccess() {
		return "redirect:/";
	}

	@GetMapping(value = "/logout/success")
	public String logoutSuccess(HttpServletRequest request) {
		String url = oauth2LogoutUri;
		try {
			if (StringUtils.isBlank(rootUrl)) {
				String homt = request.getRequestURL().toString();
				rootUrl = homt.replaceAll("/logout/success", "");
			}
			url += "?toUrl=" + URLEncoder.encode(rootUrl, "utf-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return oauth2Enabled ? "redirect:" + url : "redirect:/";
	}

	@GetMapping("/profile")
	public String profile(Model model) {
		Long userId = SecurityUtils.getLoginUserId();
		if (userId != null) {
			User user = userService.findById(userId);
			model.addAttribute("m", user);
		}
		return view("user/profile");
	}

	@PostMapping("/profile")
	public String profileSave(Model model, Long id, String fullname, String email, String oldPassword, String password,
			String confirmPassword, RedirectAttributes redirectAttributes) {
		if (password != null && !password.equals(confirmPassword)) {
			addErrorMessage(redirectAttributes, "新密码与重复密码不一致!");
			return "redirect:/profile";
		}

		Long userId = SecurityUtils.getLoginUserId();
		if (userId != null && userId.equals(id)) {
			User saved = userService.findById(userId);
			if (saved != null) {
				saved.setFullname(fullname);
				saved.setEmail(email);
				boolean hasError = false;
				if (!StringUtils.isBlank(password)) {
					if (passwordEncoder != null) {
						if (!passwordEncoder.matches(oldPassword, saved.getPassword())) {
							addErrorMessage(redirectAttributes, "原登录密码输入有误!");
							hasError = true;
						} else {
							saved.setPassword(passwordEncoder.encode(password));
						}
					} else {
						if (!saved.getPassword().equals(oldPassword)) {
							addErrorMessage(redirectAttributes, "原登录密码输入有误!");
							hasError = true;
						} else {
							saved.setPassword(password);
						}
					}
				}
				if (!hasError) {
					userService.save(saved);
					addSuccessMessage(redirectAttributes, "个人信息更新成功!");
				}
			} else {
				addErrorMessage(redirectAttributes, "未找到登录用户信息!");
			}
		}
		return "redirect:/profile";
	}

	@ModelAttribute("topnavs")
	public Iterable<Subsystem> topNavs() {
		return subsysService.findByEnabled(true);
	}

}
